using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using OWED.Network;

namespace OWED.Document
{
    public class ChangeAtomException : Exception
    {
        public ChangeAtomException(String msg)
            : base(msg)
        {

        }
    }

    [Serializable]
    public abstract class ChangeAtom
    {
        protected AbsolutePath path;

        /// <summary>
        /// Return the path of this ChangeAtom
        /// </summary>
        public AbsolutePath Path
        {
            get
            {
                return path;
            }
        }

        /// <summary>
        /// Apply the change atom to a XmlDocument, forming a XmlDocumnt
        /// that has all updates.
        /// </summary>
        /// <param name="document">document to mutate</param>
        public abstract void Apply(XmlDocument document);

        /// <summary>
        /// This undoes an apply.  So:
        /// achangeatom.Apply(doc);
        /// achangeatom.Reverse(doc);
        /// 
        /// Ends up with the same document as it started with.
        /// </summary>
        /// <param name="document">The document to apply to</param>
        public abstract void Reverse(XmlDocument document);


        public static String AtomType(ChangeAtom atom)
        {
            if ((atom as AddTag) != null)
                return "ADDT";
            if ((atom as DeleteTag) != null)
                return "DLTT";
            if ((atom as ChangeAtom) != null)
                return "CHNG";
            throw new ChangeAtomException("Non-existant type of atom!");
        }


        public abstract String Serialize();

        public static ChangeAtom DeSerialize(String atom)
        {
            throw new ChangeAtomException("DeSerialize must be overridden!");
        }

        public static ChangeAtom FromSerialized(String atom)
        {
            if (atom.Substring(0, 4) == "CHNG")
            {
                return ChangeTag.DeSerialize(atom.Substring(4));
            }
            if (atom.Substring(0, 4) == "ADDT")
            {
                return AddTag.DeSerialize(atom.Substring(4));
            } 
            if (atom.Substring(0, 4) == "DLTT")
            {
                return DeleteTag.DeSerialize(atom.Substring(4));
            }
            throw new ChangeAtomException("Can't deserialize to non-existant atom: " + 
                atom.Substring(0, 4));
        }
    }
}
